package container.queue;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * 有N张火车票，每张票都有一个编号
 * 同时有10个窗口对外售票
 * 写一个模拟程序
 *
 * @author: 李德才
 * @description:
 * @create: 2020-12-13 18:53
 **/
public class ConcurrentLinkedQueueTicket {

    /**
     * ConcurrentLinkedQueue 是一个基于链接节点的无界线程安全的队列，按照先进先出原则对元素进行排序。新元素从队列尾部插入，而获取队列元素，则需要从队列头部获取
     * 线程安全是因为使用了CAS的方式
     */

    /**
     * https://blog.csdn.net/qq_38293564/article/details/80798310
     * 在并发编程中我们有时候需要使用线程安全的队列。如果我们要实现一个线程安全的队列有两种实现方式一种是使用阻塞算法，
     * 另一种是使用非阻塞算法。使用阻塞算法的队列可以用一个锁（入队和出队用同一把锁）或两个锁（入队和出队用不同的锁）等方式来实现，
     * 而非阻塞的实现方式则可以使用循环CAS的方式来实现
     * <p>
     * ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列，它采用先进先出的规则对节点进行排序，
     * 当我们添加一个元素的时候，它会添加到队列的尾部，当我们获取一个元素时，它会返回队列头部的元素
     * <p>
     * ConcurrentLinkedQueue由head节点和tail节点组成，每个节点（Node）由节点元素（item）和指向下一个节点的引用(next)组成，
     * 节点与节点之间就是通过这个next关联起来，从而组成一张链表结构的队列。
     * <p>
     * 默认情况下head节点存储的元素为空，tail节点等于head节点
     * head = tail = new Node<E>(null);
     * <p>
     * 添加元素1：队列更新head节点的next节点为元素1节点。又因为tail节点默认情况下等于head节点，所以它们的next节点都指向元素1节点。
     * 添加元素2：队列首先设置元素1节点的next节点为元素2节点，然后更新tail节点指向元素2节点。
     * 添加元素3：设置tail节点的next节点为元素3节点。
     * 添加元素4：设置元素3的next节点为元素4节点，然后将tail节点指向元素4节点
     */


    static Queue<String> tickets = new ConcurrentLinkedQueue<>();

    static {
        /**
         *  使用 CAS操作，if (NEXT.compareAndSet(p, null, newNode))
         */
        for (int i = 0; i < 1000; i++) tickets.add("票 编号：" + i);
    }

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                while (true) {
                    /**
                     * 取出对象并从队列中删除
                     * 如果都取走了则返回空
                     * 使用CAS方式加锁
                     * if ((item = p.item) != null && p.casItem(item, null))
                     */
                    String s = tickets.poll();
                    if (s == null) break;
                    else System.out.println("销售了--" + s);
                }
            }).start();
        }
    }

}
